/** Mobile base class.
@param name The name of this mobile.
@param c Character used for this entity.
@param fg Foreground color.
@param bg Background color.
@param hp Hit points.
@param speed The speed of the mobile;
@param controllerDesc Controller description, an object containing fields named for the behaviors defined by Controller.
*/
function Mobile(name, c, fg, bg, hp, speed, controllerDesc)
{
	this.name = name;
	this.character = c;
	this.fg = fg;
	this.bg = bg;
	this.hp = hp;
	this.hpMax = hp;
	this.speed = speed;
	this.controllerDesc = controllerDesc;
	this.controller = null;
	this.skills =
	{
		unarmed: 1,
		melee: 1,
		firearms: 1
	};
	this.visibilityRange = 10;
	this.isMobile = true;
	this.init();
}
Mobile.prototype = new Entity("Mobile", "@", Color.white, Color.black, true, false);
/** Initialize routine.
 */
Mobile.prototype.init = function()
{
	this.time = Math.floor(rand.next(0, this.speed) - this.speed / 2);
	this.inventory = [];
}
Mobile.prototype.serialize = function(s)
{
	Entity.prototype.serialize.call(this, s);
	s.push(this.hp, this.hpMax, this.time);
}
Mobile.prototype.deserialize = function(s)
{
	this.time = s.pop();
	this.hpMax = s.pop();
	this.hp = s.pop();
	Entity.prototype.deserialize.call(this, s);
}
/** Add an item to this mobile's inventory.
 *@param item The item to add.
 */
Mobile.prototype.addEntity = function(item)
{
	if(item.parent)
		item.parent.removeEntity(item);
	item.parent = this;
	this.inventory.push(item);
}
/** Checks the mobile's skill against a set difficulty.
 *@param skillName The name of the skill to check.
 *@param difficulty The difficulty level to check against.
 */
Mobile.prototype.skillCheck = function(skillName, difficulty)
{
	var skill = this.skills[skillName];
	if(!skill)
		return false;
	if(!difficulty)
		return true;
	return Math.random() * 10 < ((skill - difficulty) + 5)
}
/** Attacks another mobile.
 *@param target The target of the attack.
 *@returns True if the attack was possible, false if it was not.
 */
Mobile.prototype.attack = function(target)
{
	// Range and LOS check
	if(!this.parent.isVisibleFrom(this.x, this.y, target.x, target.y, this.getCombatRange()))
		return false;

	// Skill check
	if(this.skillCheck(this.getCombatSkillName(), target.skills[target.getCombatSkillName()]))
	{
		// TODO Move the damage roll to the weapon objects
		var damage = rand.next(4, 7);
		this._doHitMessage(target, damage);
		target.takeDamage(damage, this);
	}
	else
		this._doMissMessage(target);
	return true;
}
/** Take damage.
 *@param amount The amount of damage to take.
 *@param source The source of the damage.
 */
Mobile.prototype.takeDamage = function(amount, source)
{
	this.hp -= amount;
	if(this.hp > this.hpMax)
		this.hp = this.hpMax;
	if(this.hp <= 0)
		this.die();
	if(source.isMobile &&
		this.controller)
		this.controller.wasHitBy(source);
}
/** Hit message proceedure.
 *@param target The target of the hit.
 *@param amount The amount of damage delt.
 */
Mobile.prototype._doHitMessage = function(target, amount)
{
	if(this == player)
		logWindow.pushMessage("%a0You hit the " + target.name + "! [" + amount + "]");
	else
	{
		if(target == player)
			logWindow.pushMessage("%90The " + this.name + " hit you! [" + amount + "]");
		else
			logWindow.pushMessage("%f0The " + this.name + " hit the " + target.name + ". [" + amount + "]");
	}
}
/** Miss message proceedure.
 *@param target The target of the missed attack.
 */
Mobile.prototype._doMissMessage = function(target)
{
	if(this == player)
		logWindow.pushMessage("%90You miss the " + target.name + ".");
	else
	{
		if(target == player)
			logWindow.pushMessage("%a0The " + this.name + " missed you.");
		else
			logWindow.pushMessage("%f0The " + this.name + " missed the " + target.name + ".");
	}
}
/** Death message proceedure.
 */
Mobile.prototype._doDeathMessage = function()
{
	if(this == player)
		logWindow.pushMessage("%90You died.");
	else
		logWindow.pushMessage("%a0The " + this.name + " died.");
}
/** Death proceedure.
 */
Mobile.prototype.die = function()
{
	this._doDeathMessage();
	var corpse = this.getCorpseEntity();
	corpse.x = this.x;
	corpse.y = this.y;
	var parent = this.parent;
	parent.removeEntity(this);
	parent.addEntity(corpse);
}
/** Gets the corpse entity for this mobile.
 */
Mobile.prototype.getCorpseEntity = function()
{
	return new CorpseEntity();
}
/** Returns the mobile's current combat skill.
 */
Mobile.prototype.getCombatSkillName = function()
{
	// TODO Get skill name from weapon object
	return "unarmed";
}
/** Returns the mobile's combat range.
 */
Mobile.prototype.getCombatRange = function()
{
	// TODO Get this from the weapon object
	return 1;
}
/** Do a turn for this mobile.
 */
Mobile.prototype.doTurn = function()
{
	this.controller.doTurn();
	return;
}
/** Create this mobile's controller.
 *
 * This should be called once for every mobile when the player enters the map.
 */
Mobile.prototype.createController = function()
{
	this.controller = new Controller(
		this,
		this.controllerDesc.sense,
		this.controllerDesc.alert,
		this.controllerDesc.idle,
		this.controllerDesc.wimpy,
		this.controllerDesc.flee,
		this.controllerDesc.attack,
		this.controllerDesc.follow
	);
}
